/**
 * @(#)SymbolTable.java, 2008-4-30.
 * Copyright 2008  Program Analysis Research Group(PARG),Institute of Software, Peking University.
 * All rights reserved.
 */
package edu.pku.sei.pgie.analyzer.core;

import java.util.HashMap;
import java.util.Iterator;

import org.eclipse.core.resources.IFolder;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import edu.pku.sei.pgie.analyzer.util.ASTUtil;

/**
 * @author HeLi
 */
public class SymbolTable {
    IPackageFragmentRoot root;

    HashMap<String, Integer> fqnSymbols;

    boolean isCached;

    int refIndex;

    public SymbolTable(IJavaProject javaProject) {
        IFolder srcFolder = javaProject.getProject().getFolder("src");
        IPackageFragmentRoot root = javaProject
                .getPackageFragmentRoot(srcFolder);
        this.root = root;
        isCached = false;
        fqnSymbols = new HashMap<String, Integer>();
        refIndex = 0;
    }

    public String[] getFqns() {
        if (!isCached)
            buildSymbol();
        String[] fqns = new String[fqnSymbols.size()];
        Iterator iterator = fqnSymbols.keySet().iterator();
        int i = 0;
        while (iterator.hasNext()) {
            fqns[i++] = (String) iterator.next();
        }
        return fqns;
    }

    public boolean hasSymbol(String fqn) {
        if (!isCached)
            buildSymbol();
        return fqnSymbols.containsKey(fqn);
    }

    public String resolveRefId(String fqn) {
        if (!isCached)
            buildSymbol();
        if (fqnSymbols.containsKey(fqn)) {
            return fqnSymbols.get(fqn).toString();
        }
        return null;
    }

    class SymbolVisitor extends ASTVisitor {
        public SymbolVisitor() {}

        public boolean visit(TypeDeclaration node) {
            ITypeBinding typeBinding = node.resolveBinding();
            fqnSymbols.put(typeBinding.getQualifiedName(), new Integer(
                    refIndex++));
            return true;
        }
    }

    public void buildSymbol() {
        if (isCached)
            return;
        ICompilationUnit[] compilationUnits = null;

        ASTParser parser = ASTParser.newParser(AST.JLS3);
        parser.setResolveBindings(true);
        parser.setProject(root.getJavaProject());

        try {
            compilationUnits = ASTUtil.collectCompilationUnit(this.root);
            ASTRequestor requestor = new ASTRequestor() {
                public void acceptAST(ICompilationUnit source,
                        CompilationUnit ast) {
                    ast.accept(new SymbolVisitor());
                }
            };
            parser.createASTs(compilationUnits, new String[] {}, requestor,
                    null);
        } catch (JavaModelException e) {
            e.printStackTrace();
        } finally {
            isCached = true;
        }

    }
}
